/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2015 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = shortTCP_core.c                                               */
/*  NOTE      =                                                               */
/*  DATE      = 2015/01/16 by geyh                                            */
/******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "frmem.h"
#include "frsutl.h"
#include "shortTCP_core.h"
#include "module.h"
#include "module_comm.h"
#include "frct_comm.h"
#include "frreport_comm.h"

/*
 *  未知协议的公用私有数据,挂在session下
*/
typedef struct __st_L7session_shortTCP_private {
    unsigned long ul_seq;                              /* 序列号，1次req和response时，使用同一个序列号 */
    //char arr_session_id[APM_UUID_SIZE];              /* session ID, UUID */
   L4_transaction st_l4_trans;                         /* 数据 */

}L7session_shortTCP_private;

/*******************************************************************************
*  FUNC     :  创建L7session_shortTCP_private
*  ARGS     :  void
*  RTN      :  NULL                         (失败)
*           :  p_st_shortTCP_private        (成功)
*  NOTE     :
*******************************************************************************/
static L7session_shortTCP_private* shortTCP_private_create(void)
{
    L7session_shortTCP_private *p_st_shortTCP_private = NULL;

    //申请内存并初始化
    p_st_shortTCP_private = frmalloc(sizeof(L7session_shortTCP_private));
    if(p_st_shortTCP_private == NULL)
        return NULL;

    memset(p_st_shortTCP_private,'\0',sizeof(L7session_shortTCP_private));

    return p_st_shortTCP_private;

}

/*******************************************************************************
*  FUNC     :  shortTCP_data格式化
*  ARGS     :  p_st_conn                    p_st_conn(入力链接信息)
*           :  i_use_request                1.FR_YES  (request)   2.FR_NO (response)
*           :  p_st_hash_report             p_st_hash_report(保存Frreport_data)
*           :  p_st_l4_private              shortTCP私有数据
*  RTN      :  FR_FAIL                      (失败)
*           :  FR_SUCC                      (成功)
*  NOTE     :
*******************************************************************************/
static int shortTCP_data_format(Conntrack *p_st_conn
                        , int i_use_request
                        , Frhash_header *p_st_hash_report
                        , L4_transaction *p_st_l4_private
                        , unsigned long ul_seq)
{
    int i_ret = FR_FAIL;
    Frtrans_info  st_trans_info;
    L4_transaction *p_st_l4_trans = NULL;

    if(p_st_l4_private == NULL || p_st_conn == NULL)
        return FR_FAIL;

    memset(&st_trans_info,0x00,sizeof(Frtrans_info));
    p_st_l4_trans = &(st_trans_info.st_l4_trans);
    //设置p_st_l4_trans
    if(i_use_request == FR_YES)
    {
        memcpy(p_st_l4_trans,p_st_l4_private,sizeof(L4_transaction));

        i_ret = frreport_add_l7data(p_st_hash_report, p_st_conn, &st_trans_info
                                    , FR_YES, 1, FR_NO, NULL, NULL, ul_seq);
        return i_ret;
    }
    else
    {
       //st_response_time_first_byte
        memcpy(p_st_l4_trans,p_st_l4_private,sizeof(L4_transaction));

        i_ret = frreport_add_l7data(p_st_hash_report, p_st_conn, &st_trans_info
                                    , FR_YES, 1, FR_YES, NULL, NULL, ul_seq);
        return i_ret;
    }
}

/*******************************************************************************
*  FUNC     :  shortTCP的packet解析
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_data_in(入力packet信息)
            :  p_st_hash_report(保存Frreport_data)
*  RTN      :  FR_FAIL          (失败)
*           :  FR_SUCC          (成功)
*  NOTE     :
*******************************************************************************/
int shortTCP_data_analysis(Conntrack *p_st_conn
                      , Analyze_data_in *p_st_data_in
                      , Frhash_header *p_st_hash_report)
{
    L7_session *p_st_session = NULL;                   /* L7session */
    L7session_shortTCP_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_SUCC;

    //如果不是从SYN建立开始的连接，我们不分析
    if(p_st_session->p_session_private == NULL)
    {
        //如果是 SYN 包
        if (p_st_data_in->em_analyz_cmd == FRANALYZ_CMD_SYN)
        {
            p_st_session->p_session_private = shortTCP_private_create();
            //内存分配失败
            if(p_st_session->p_session_private == NULL)
                return APM_L7_ANALYZE_SUCC;
        }
        else
            return APM_L7_ANALYZE_SUCC;
    }

    p_st_private = p_st_session->p_session_private;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    //fin 包
    if(p_st_data_in->em_analyz_cmd == FRANALYZ_CMD_FIN)
    {
        //应答完成时间戳
        p_st_l4_trans->st_response_time.tv_sec = p_st_data_in->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time.tv_usec = p_st_data_in->st_timestamp.tv_usec;
        //应答时间
        p_st_l4_trans->ul_response_time_us = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte)
                , &(p_st_l4_trans->st_response_time));

        //如果有请求，发送应答数据
        if(p_st_l4_trans->st_request_time_first_byte.tv_sec != 0 ||  p_st_l4_trans->st_request_time_first_byte.tv_usec != 0)
        {
            if(p_st_private->ul_seq == 0)
                p_st_private->ul_seq = frct_seq_increase(p_st_conn);
            shortTCP_data_format(p_st_conn, FR_YES, p_st_hash_report, &(p_st_private->st_l4_trans), p_st_private->ul_seq);
        }

        shortTCP_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    //request
    if(p_st_data_in->i_direction == FR_DIRECT_CLIENT2SRV) {
        if(p_st_l4_trans->st_request_time_first_byte.tv_sec == 0 &&
            p_st_l4_trans->st_request_time_first_byte.tv_usec == 0)
        {
            //第一个包  st_request_time_first_byte
            p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_data_in->st_timestamp.tv_sec;
            p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_data_in->st_timestamp.tv_usec;
        }
        /* 请求的字节数 */
        p_st_l4_trans->l_request_bytes += p_st_data_in->ui_payload_len;
        return APM_L7_ANALYZE_SUCC;
    }

    //response
    if(p_st_data_in->i_direction == FR_DIRECT_SRV2CLIENT) {
        if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0 &&
                p_st_l4_trans->st_response_time_first_byte.tv_usec == 0) {
            //收到第一个响应包  上报请求数据
            p_st_private->ul_seq = frct_seq_increase(p_st_conn);
            shortTCP_data_format(p_st_conn, FR_YES, p_st_hash_report, &(p_st_private->st_l4_trans), p_st_private->ul_seq);

            //应答发起时间戳
            p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_data_in->st_timestamp.tv_sec;
            p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_data_in->st_timestamp.tv_usec;

            //首包时间
            p_st_l4_trans->ul_response_time_firstbyte_us = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &(p_st_l4_trans->st_response_time_first_byte));
        }
        p_st_l4_trans->l_response_bytes += p_st_data_in->ui_payload_len;
        return APM_L7_ANALYZE_SUCC;
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断是否是TCP协议
*  ARGS     :  p_st_conn                    输入数据信息
*           :  p_st_data_in                 输入数据
*  RTN      :  APM_L7_IS_NO                 不属于TCP协议
*           :  APM_L7_IS_YES                属于TCP协议
*  NOTE     :
*******************************************************************************/
int shortTCP_detect(Conntrack *p_st_conn, Analyze_data_in *p_st_data_in)
{
    //判断是否属于TCP
    return p_st_conn->ip_proto == IPPROTO_TCP ? APM_L7_IS_YES : APM_L7_IS_NO;
}


/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session(shortTCP的私有session数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int shortTCP_session_destroy(void *p_private_session)
{
    if(p_private_session != NULL)
        frfree(p_private_session);
    return FR_SUCC;
}
